// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-==-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= //
//  »Project«   Talina Gaming System (TgS) (∂)
//  »File«      TgS Common - Geometry 3D - Mesh [Utility].c_inc
//  »Author«    Andrew Aye (EMail: mailto:andrew.aye@gmail.com, Web: http://www.andrewaye.com)
//  »Version«   4.0
// ------------------------------------------------------------------------------------------------------------------------------ //
//  Copyright: © 2002-2010, Andrew Aye.  All Rights Reserved.
//  This software is free for non-commercial use. Redistribution and use in source and binary forms, with or without modification,
//  are permitted provided that the following conditions are met: 
//    Redistributions of source code must retain this copyright notice, this list of conditions and the following disclaimers. 
//    Redistributions in binary form must reproduce this copyright notice, this list of conditions and the following
//      disclaimers in the documentation and other materials provided with the distribution. 
//  Neither the names of the copyright owner nor the names of its contributors may be used to endorse or promote products derived
//  from this software without specific prior written permission. 
//  The intellectual property rights of the algorithms used reside with Andrew Aye.  You may not use this software, in whole or
//  in part, in support of any commercial product without the express written consent of the author.
//  There is no warranty or other guarantee of fitness of this software for any purpose. It is provided solely "as is".
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-==-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= //

// -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. //
//  Mesh Simple
// -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. //

TYPE FI(tgGM_Volume_MS)( V(CPCU_TgMESH_SIMPLE) ptgMS1 )
{
    TYPE                                tyVolume = MKL(0.0);
    TgMESH_ITER                         itMS;
    TgUINT32                            uiIndex;

    FI(tgGM_Iterator_Init_MS)( &itMS, ptgMS1 );

    for (uiIndex = 0; uiIndex < itMS.m_nuiFace; ++uiIndex)
    {
        V(CPCU_TgVEC)                       ptvS0 = ptgMS1->m_ptvVert_List + FI(tgGM_Iterator_Incr_MS)( &itMS, ptgMS1 );
        V(CPCU_TgVEC)                       ptvS1 = ptgMS1->m_ptvVert_List + FI(tgGM_Iterator_Incr_MS)( &itMS, ptgMS1 );
        V(CPCU_TgVEC)                       ptvS2 = ptgMS1->m_ptvVert_List + FI(tgGM_Iterator_Incr_MS)( &itMS, ptgMS1 );
        V(C_TgVEC)                          tvE0 = V(F_SUB_VV)( ptvS1, ptvS0 );
        V(C_TgVEC)                          tvE2 = V(F_SUB_VV)( ptvS2, ptvS0 );
        const TYPE                          tyNx = tvE0.m.y*tvE2.m.z - tvE0.m.z*tvE2.m.y;
        const TYPE                          tyNy = tvE0.m.z*tvE2.m.x - tvE0.m.x*tvE2.m.z;
        const TYPE                          tyNz = tvE0.m.x*tvE2.m.y - tvE0.m.y*tvE2.m.x;
        const TYPE                          tyTriD = tyNx*ptvS0->m.x + tyNy*ptvS0->m.y + tyNz*ptvS0->m.z;

        TYPE                                tyDA, tyDB, tyAA, tyBB, tyC1, tyCA, tyCB, tyP1, tyPA, tyPB;
        TgSINT32                            i0, i1, i2;

        if (tyNx > tyNy && tyNx > tyNz)
        {
            i2 = 0;
        }
        else
        {
            i2 = (tyNy > tyNz) ? 1 : 2;
        };

        i0 = (i2 + 1) % 3;
        i1 = (i2 + 2) % 3;

        tyDA = ptvS1->m.x - ptvS0->m.x;
        tyDB = ptvS1->m.y - ptvS0->m.y;
        tyAA = ptvS0->m.x * ptvS0->m.x;
        tyBB = ptvS0->m.y * ptvS0->m.y;

        tyC1 = ptvS1->m.x + ptvS0->m.x;
        tyCA = ptvS1->m.x * tyC1 + tyAA;
        tyCB = ptvS1->m.y * (ptvS1->m.y + ptvS0->m.y) + tyBB;

        tyP1 = tyDB * tyC1;
        tyPA = tyDB * tyCA;
        tyPB = tyDA * tyCB;

        tyDA = ptvS2->m.x - ptvS1->m.x;
        tyDB = ptvS2->m.y - ptvS1->m.y;
        tyAA = ptvS1->m.x * ptvS1->m.x;
        tyBB = ptvS1->m.y * ptvS1->m.y;

        tyC1 = ptvS2->m.x + ptvS1->m.x;
        tyCA = ptvS2->m.x * tyC1 + tyAA;
        tyCB = ptvS2->m.y * (ptvS2->m.y + ptvS1->m.y) + tyBB;

        tyP1 += tyDB * tyC1;
        tyPA += tyDB * tyCA;
        tyPB += tyDA * tyCB;

        tyDA = ptvS0->m.x - ptvS2->m.x;
        tyDB = ptvS0->m.y - ptvS2->m.y;
        tyAA = ptvS2->m.x * ptvS2->m.x;
        tyBB = ptvS2->m.y * ptvS2->m.y;

        tyC1 = ptvS0->m.x + ptvS2->m.x;
        tyCA = ptvS0->m.x * tyC1 + tyAA;
        tyCB = ptvS0->m.y * (ptvS0->m.y + ptvS2->m.y) + tyBB;

        tyP1 += tyDB * tyC1;
        tyPA += tyDB * tyCA;
        tyPB += tyDA * tyCB;

        tyP1 /= MKL( 2.0);
        tyPA /= MKL( 6.0);
        tyPB /= MKL(-6.0);

        if (i0 == 0) // 0,1,2
        {
            tyVolume += tyNx * tyPA / tyNz;
        }
        else if (i1 == 0) // 2,0,1
        {
            tyVolume += tyNz * tyPB / tyNy;
        }
        else // 1,2,0
        {
            tyVolume += (tyNy / -(tyNx * tyNx)) * (tyNy * tyPA + tyNz * tyPB - tyTriD * tyP1);
        };
    };

    return (tyVolume);
}


TYPE FI(tgGM_Area_MS)( V(CPCU_TgMESH_SIMPLE) ptgMS1 )
{
    TYPE                                tyArea = MKL(0.0);
    TgMESH_ITER                         itMS;
    TgUINT32                            uiIndex;

    FI(tgGM_Iterator_Init_MS)( &itMS, ptgMS1 );

    for (uiIndex = 0; uiIndex < itMS.m_nuiFace; ++uiIndex)
    {
        V(CPCU_TgVEC)                       ptvS0 = ptgMS1->m_ptvVert_List + FI(tgGM_Iterator_Incr_MS)( &itMS, ptgMS1 );
        V(CPCU_TgVEC)                       ptvS1 = ptgMS1->m_ptvVert_List + FI(tgGM_Iterator_Incr_MS)( &itMS, ptgMS1 );
        V(CPCU_TgVEC)                       ptvS2 = ptgMS1->m_ptvVert_List + FI(tgGM_Iterator_Incr_MS)( &itMS, ptgMS1 );
        V(C_TgVEC)                          tvE0 = V(F_SUB_VV)( ptvS1, ptvS0 );
        V(C_TgVEC)                          tvE2 = V(F_SUB_VV)( ptvS2, ptvS0 );
        V(C_TgVEC)                          tvNM = V(F_CX)( &tvE0, &tvE2 );

        tyArea += MKL(0.5)*V(F_LEN)( &tvNM );
    };

    return (tyArea);
}


TgBOOL FI(tgGM_Is_Contained_MS)( V(CPCU_TgMESH_SIMPLE) ptgMS1, V(CPCU_TgVEC) ptvS3 )
{
    TgMESH_ITER                         itMS;
    TgUINT32                            uiIndex;

    FI(tgGM_Iterator_Init_MS)( &itMS, ptgMS1 );

    for (uiIndex = 0; uiIndex < itMS.m_nuiFace; ++uiIndex)
    {
        V(CPCU_TgVEC)                       ptvS0 = ptgMS1->m_ptvVert_List + FI(tgGM_Iterator_Incr_MS)( &itMS, ptgMS1 );
        V(CPCU_TgVEC)                       ptvS1 = ptgMS1->m_ptvVert_List + FI(tgGM_Iterator_Incr_MS)( &itMS, ptgMS1 );
        V(CPCU_TgVEC)                       ptvS2 = ptgMS1->m_ptvVert_List + FI(tgGM_Iterator_Incr_MS)( &itMS, ptgMS1 );
        V(C_TgVEC)                          tvE0 = V(F_SUB_VV)( ptvS1, ptvS0 );
        V(C_TgVEC)                          tvE2 = V(F_SUB_VV)( ptvS2, ptvS0 );
        V(C_TgVEC)                          tvNM = V(F_CX)( &tvE0, &tvE2 );
        V(C_TgVEC)                          tvX0 = V(F_SUB_VV)( ptvS3, ptvS0 );

        if (MKL(0.0) >= V(F_DOT3_VV)( &tvNM, &tvX0 ))
        {
            return (TgFALSE);
        };
    };

    return (TgTRUE);
}


// -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. //
//  Mesh BA
// -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. //

TgVOID FI(tgGM_Update_Face_BA_MA)( V(PCU_TgMESH_BA) ptgMA0 )
{
    TgMESH_ITER                         itMS;
    TgUINT32                            uiFace;

    FI(tgGM_Iterator_Init_MS)( &itMS, &ptgMA0->m_tgMS );

    ptgMA0->m_tvCG[0] = V(TgKV_ZERO);

    if (ETgSWEEP_ROTATIONAL == ptgMA0->m_etgSweep)
    {
        for (uiFace = 0; uiFace < itMS.m_nuiFace; ++uiFace)
        {
            C_TgUINT32                          uiI0 = FI(tgGM_Iterator_Incr_MS)( &itMS, &ptgMA0->m_tgMS );
            C_TgUINT32                          uiI1 = FI(tgGM_Iterator_Incr_MS)( &itMS, &ptgMA0->m_tgMS );
            C_TgUINT32                          uiI2 = FI(tgGM_Iterator_Incr_MS)( &itMS, &ptgMA0->m_tgMS );

            V(CPCU_TgVEC)                       ptvX0 = ptgMA0->m_tgMS.m_ptvVert_List + uiI0;
            V(CPCU_TgVEC)                       ptvX1 = ptgMA0->m_tgMS.m_ptvVert_List + uiI1;
            V(CPCU_TgVEC)                       ptvX2 = ptgMA0->m_tgMS.m_ptvVert_List + uiI2;

            V(C_TgVEC)                          tvX3 = V(F_ADD_VV)( ptvX0, ptgMA0->m_ptvVert_DT + uiI0 );
            V(C_TgVEC)                          tvX4 = V(F_ADD_VV)( ptvX1, ptgMA0->m_ptvVert_DT + uiI1 );
            V(C_TgVEC)                          tvX5 = V(F_ADD_VV)( ptvX2, ptgMA0->m_ptvVert_DT + uiI2 );

            V(tgGM_Init_PT_BA)(  ptgMA0->m_ptgBA + uiFace, ptvX0 );
            V(tgGM_Union_PT_BA)( ptgMA0->m_ptgBA + uiFace, ptvX1 );
            V(tgGM_Union_PT_BA)( ptgMA0->m_ptgBA + uiFace, ptvX2 );
            V(tgGM_Union_PT_BA)( ptgMA0->m_ptgBA + uiFace, &tvX3 );
            V(tgGM_Union_PT_BA)( ptgMA0->m_ptgBA + uiFace, &tvX4 );
            V(tgGM_Union_PT_BA)( ptgMA0->m_ptgBA + uiFace, &tvX5 );
        };
    }
    else if (ETgSWEEP_LINEAR == ptgMA0->m_etgSweep)
    {
        for (uiFace = 0; uiFace < itMS.m_nuiFace; ++uiFace)
        {
            C_TgUINT32                          uiI0 = FI(tgGM_Iterator_Incr_MS)( &itMS, &ptgMA0->m_tgMS );
            C_TgUINT32                          uiI1 = FI(tgGM_Iterator_Incr_MS)( &itMS, &ptgMA0->m_tgMS );
            C_TgUINT32                          uiI2 = FI(tgGM_Iterator_Incr_MS)( &itMS, &ptgMA0->m_tgMS );

            V(CPCU_TgVEC)                       ptvX0 = ptgMA0->m_tgMS.m_ptvVert_List + uiI0;
            V(CPCU_TgVEC)                       ptvX1 = ptgMA0->m_tgMS.m_ptvVert_List + uiI1;
            V(CPCU_TgVEC)                       ptvX2 = ptgMA0->m_tgMS.m_ptvVert_List + uiI2;

            V(tgGM_Init_PT_BA)(  ptgMA0->m_ptgBA + uiFace, ptvX0 );
            V(tgGM_Union_PT_BA)( ptgMA0->m_ptgBA + uiFace, ptvX1 );
            V(tgGM_Union_PT_BA)( ptgMA0->m_ptgBA + uiFace, ptvX2 );
            V(tgGM_Sweep_BA)( ptgMA0->m_ptgBA + uiFace, &ptgMA0->m_tgDT.m_tvDT );
        };
    }
    else if (ETgSWEEP_STATIC == ptgMA0->m_etgSweep)
    {
        for (uiFace = 0; uiFace < itMS.m_nuiFace; ++uiFace)
        {
            C_TgUINT32                          uiI0 = FI(tgGM_Iterator_Incr_MS)( &itMS, &ptgMA0->m_tgMS );
            C_TgUINT32                          uiI1 = FI(tgGM_Iterator_Incr_MS)( &itMS, &ptgMA0->m_tgMS );
            C_TgUINT32                          uiI2 = FI(tgGM_Iterator_Incr_MS)( &itMS, &ptgMA0->m_tgMS );

            V(CPCU_TgVEC)                       ptvX0 = ptgMA0->m_tgMS.m_ptvVert_List + uiI0;
            V(CPCU_TgVEC)                       ptvX1 = ptgMA0->m_tgMS.m_ptvVert_List + uiI1;
            V(CPCU_TgVEC)                       ptvX2 = ptgMA0->m_tgMS.m_ptvVert_List + uiI2;

            V(tgGM_Init_PT_BA)(  ptgMA0->m_ptgBA + uiFace, ptvX0 );
            V(tgGM_Union_PT_BA)( ptgMA0->m_ptgBA + uiFace, ptvX1 );
            V(tgGM_Union_PT_BA)( ptgMA0->m_ptgBA + uiFace, ptvX2 );
        };
    };
}


TgVOID FI(tgGM_Update_Face_CG_BA_MA)( V(PCU_TgMESH_BA) ptgMA0 )
{
    TgMESH_ITER                         itMS;
    TgUINT32                            uiFace;

    FI(tgGM_Iterator_Init_MS)( &itMS, &ptgMA0->m_tgMS );

    ptgMA0->m_tvCG[0] = V(TgKV_ZERO);

    if (ETgSWEEP_ROTATIONAL == ptgMA0->m_etgSweep)
    {
        for (uiFace = 0; uiFace < itMS.m_nuiFace; ++uiFace)
        {
            C_TgUINT32                          uiI0 = FI(tgGM_Iterator_Incr_MS)( &itMS, &ptgMA0->m_tgMS );
            C_TgUINT32                          uiI1 = FI(tgGM_Iterator_Incr_MS)( &itMS, &ptgMA0->m_tgMS );
            C_TgUINT32                          uiI2 = FI(tgGM_Iterator_Incr_MS)( &itMS, &ptgMA0->m_tgMS );

            V(CPCU_TgVEC)                       ptvX0 = ptgMA0->m_tgMS.m_ptvVert_List + uiI0;
            V(CPCU_TgVEC)                       ptvX1 = ptgMA0->m_tgMS.m_ptvVert_List + uiI1;
            V(CPCU_TgVEC)                       ptvX2 = ptgMA0->m_tgMS.m_ptvVert_List + uiI2;

            V(C_TgVEC)                          tvX3 = V(F_ADD_VV)( ptvX0, ptgMA0->m_ptvVert_DT + uiI0 );
            V(C_TgVEC)                          tvX4 = V(F_ADD_VV)( ptvX1, ptgMA0->m_ptvVert_DT + uiI1 );
            V(C_TgVEC)                          tvX5 = V(F_ADD_VV)( ptvX2, ptgMA0->m_ptvVert_DT + uiI2 );

            V(C_TgVEC)                          tvX6 = V(F_ADD_VV)( ptvX1, ptvX2 );
            V(C_TgVEC)                          tvX7 = V(F_ADD_VV)( &tvX4, &tvX5 );
            V(C_TgVEC)                          tvX8 = V(F_ADD_VV)( ptvX0, &tvX6 );
            V(C_TgVEC)                          tvX9 = V(F_ADD_VV)( &tvX3, &tvX7 );

            ptgMA0->m_tvCG[0] = V(F_ADD_VV)( ptgMA0->m_tvCG + 0, &tvX8 );
            ptgMA0->m_tvCG[1] = V(F_ADD_VV)( ptgMA0->m_tvCG + 1, &tvX9 );

            V(tgGM_Init_PT_BA)(  ptgMA0->m_ptgBA + uiFace, ptvX0 );
            V(tgGM_Union_PT_BA)( ptgMA0->m_ptgBA + uiFace, ptvX1 );
            V(tgGM_Union_PT_BA)( ptgMA0->m_ptgBA + uiFace, ptvX2 );
            V(tgGM_Union_PT_BA)( ptgMA0->m_ptgBA + uiFace, &tvX3 );
            V(tgGM_Union_PT_BA)( ptgMA0->m_ptgBA + uiFace, &tvX4 );
            V(tgGM_Union_PT_BA)( ptgMA0->m_ptgBA + uiFace, &tvX5 );
        };

        ptgMA0->m_tvCG[0] = V(F_DIV_VS)( ptgMA0->m_tvCG + 0, (TYPE)(itMS.m_nuiFace * MKL(3.0)) );
        ptgMA0->m_tvCG[1] = V(F_DIV_VS)( ptgMA0->m_tvCG + 1, (TYPE)(itMS.m_nuiFace * MKL(3.0)) );
    }
    else if (ETgSWEEP_LINEAR == ptgMA0->m_etgSweep)
    {
        for (uiFace = 0; uiFace < itMS.m_nuiFace; ++uiFace)
        {
            C_TgUINT32                          uiI0 = FI(tgGM_Iterator_Incr_MS)( &itMS, &ptgMA0->m_tgMS );
            C_TgUINT32                          uiI1 = FI(tgGM_Iterator_Incr_MS)( &itMS, &ptgMA0->m_tgMS );
            C_TgUINT32                          uiI2 = FI(tgGM_Iterator_Incr_MS)( &itMS, &ptgMA0->m_tgMS );

            V(CPCU_TgVEC)                       ptvX0 = ptgMA0->m_tgMS.m_ptvVert_List + uiI0;
            V(CPCU_TgVEC)                       ptvX1 = ptgMA0->m_tgMS.m_ptvVert_List + uiI1;
            V(CPCU_TgVEC)                       ptvX2 = ptgMA0->m_tgMS.m_ptvVert_List + uiI2;
            V(C_TgVEC)                          tvX3 = V(F_ADD_VV)( ptvX1, ptvX2 );
            V(C_TgVEC)                          tvX4 = V(F_ADD_VV)( ptvX0, &tvX3 );

            ptgMA0->m_tvCG[0] = V(F_ADD_VV)( ptgMA0->m_tvCG + 0, &tvX4 );

            V(tgGM_Init_PT_BA)(  ptgMA0->m_ptgBA + uiFace, ptvX0 );
            V(tgGM_Union_PT_BA)( ptgMA0->m_ptgBA + uiFace, ptvX1 );
            V(tgGM_Union_PT_BA)( ptgMA0->m_ptgBA + uiFace, ptvX2 );
            V(tgGM_Sweep_BA)( ptgMA0->m_ptgBA + uiFace, &ptgMA0->m_tgDT.m_tvDT );
        };

        ptgMA0->m_tvCG[0] = V(F_DIV_VS)( ptgMA0->m_tvCG + 0, (TYPE)(itMS.m_nuiFace * MKL(3.0)) );
        ptgMA0->m_tvCG[1] = V(F_ADD_VV)( ptgMA0->m_tvCG + 0, &ptgMA0->m_tgDT.m_tvDT );
    }
    else if (ETgSWEEP_STATIC == ptgMA0->m_etgSweep)
    {
        for (uiFace = 0; uiFace < itMS.m_nuiFace; ++uiFace)
        {
            C_TgUINT32                          uiI0 = FI(tgGM_Iterator_Incr_MS)( &itMS, &ptgMA0->m_tgMS );
            C_TgUINT32                          uiI1 = FI(tgGM_Iterator_Incr_MS)( &itMS, &ptgMA0->m_tgMS );
            C_TgUINT32                          uiI2 = FI(tgGM_Iterator_Incr_MS)( &itMS, &ptgMA0->m_tgMS );

            V(CPCU_TgVEC)                       ptvX0 = ptgMA0->m_tgMS.m_ptvVert_List + uiI0;
            V(CPCU_TgVEC)                       ptvX1 = ptgMA0->m_tgMS.m_ptvVert_List + uiI1;
            V(CPCU_TgVEC)                       ptvX2 = ptgMA0->m_tgMS.m_ptvVert_List + uiI2;
            V(C_TgVEC)                          tvX3 = V(F_ADD_VV)( ptvX1, ptvX2 );
            V(C_TgVEC)                          tvX4 = V(F_ADD_VV)( ptvX0, &tvX3 );

            ptgMA0->m_tvCG[0] = V(F_ADD_VV)( ptgMA0->m_tvCG + 0, &tvX4 );

            V(tgGM_Init_PT_BA)(  ptgMA0->m_ptgBA + uiFace, ptvX0 );
            V(tgGM_Union_PT_BA)( ptgMA0->m_ptgBA + uiFace, ptvX1 );
            V(tgGM_Union_PT_BA)( ptgMA0->m_ptgBA + uiFace, ptvX2 );
        };

        ptgMA0->m_tvCG[0] = V(F_DIV_VS)( ptgMA0->m_tvCG + 0, (TYPE)(itMS.m_nuiFace * MKL(3.0)) );
        ptgMA0->m_tvCG[1] = V(TgKV_ZERO);
    };
}